/*
 * MouseOut.java
 *
 * Created on December 6, 2007, 1:16 PM
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package io;

import java.awt.AWTException;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.util.HashMap;
import java.util.List;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.matchers.VarMatcher;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;

import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.SetProperty;
import tal.drivechain.variable.Variable;


/**
 *
 * @author Main
 */
public class MouseOut extends Module {
    private List<Object[]> triggerAction;
    Robot r = null;
    
    @Override
    public void setupProperties() throws IllegalArgumentException, AbortChainException {
        setTriggerAction(props.getProperty("triggerAction"), null);
    }

    public void setTriggerAction(Object value, SetProperty.Flag flag) {
        List<Object[]> newTrigAction = (List<Object[]>)value;

        if (flag == SetProperty.Flag.ADD || triggerAction==null)
            triggerAction = newTrigAction;
        else triggerAction.addAll(newTrigAction);
    } public Object getTriggerAction() { return triggerAction; }

    @Override
    public void stop() {
        r = null;
        super.stop();
    }

    @Override
    public void start() {
        super.start();
        try {
            r = new Robot();
            r.setAutoWaitForIdle(true);
        } catch (AWTException ex) {
            log("Error while initializing key robot: " + ex.getMessage(), MSG.ERROR);
        }
    }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
        this.setInVars(in, timestamp, channel);
        for (Object[] item : triggerAction) {
            VarMatcher trigger = (VarMatcher)item[0];
            if (trigger.matches(in, channel, this)) {
                Object[] action = (Object[])item[1];
                int type = (Integer)action[0];
                int id = (Integer)action[1];
                Variable val = (Variable)action[2];
                int ival = (Integer)DataType.INT.cast(val.getValue(this));
                switch(type) {
                    case ACTION_MOVE:
                        if (id==ID_X) {
                            if (infoFlag)
                                log("Moving mouse pointer x coordinate to " + ival, MSG.INFO);
                            r.mouseMove(ival, MouseInfo.getPointerInfo().getLocation().y);
                        } else if (id==ID_Y) {
                            if (infoFlag)
                                log("Moving mouse pointer y coordinate to " + ival, MSG.INFO);
                            r.mouseMove(MouseInfo.getPointerInfo().getLocation().x, ival);
                        } else if (id==ID_WHEEL) {
                            if (infoFlag)
                                log("Moving mouse wheel " + ival + " notches", MSG.INFO);
                            r.mouseWheel(ival);
                        } else log("Invalid id for type move: " + actionIdToString(id, null), MSG.WARNING);
                        break;
                    case ACTION_MOVE_RELATIVE:
                        if (id==ID_X) {
                            Point p = MouseInfo.getPointerInfo().getLocation();
                            if (infoFlag)
                                log("Moving mouse pointer x coordinate to " + (p.x+ival), MSG.INFO);
                            r.mouseMove(p.x+ival, p.y);
                        } else if (id==ID_Y) {
                            Point p = MouseInfo.getPointerInfo().getLocation();
                            if (infoFlag)
                                log("Moving mouse pointer y coordinate to " + (p.y+ival), MSG.INFO);
                            r.mouseMove(p.x, p.y+ival);
                        } else log("Invalid id for type move.rel: " + actionIdToString(id, null), MSG.WARNING);
                        break;
                    case ACTION_BUTTON:
                        if (id==ID_LEFT) {
                            if (ival==0) {
                                if (infoFlag)
                                    log("Releasing left button.", MSG.INFO);
                                r.mouseRelease(InputEvent.BUTTON1_MASK);
                            } else {
                                if (infoFlag)
                                    log("Pressing left button.", MSG.INFO);
                                r.mousePress(InputEvent.BUTTON1_MASK);
                            }
                        } else if (id==ID_MIDDLE) {
                            if (ival==0) {
                                if (infoFlag)
                                    log("Releasing middle button.", MSG.INFO);
                                r.mouseRelease(InputEvent.BUTTON2_MASK);
                            } else {
                                if (infoFlag)
                                    log("Pressing middle button.", MSG.INFO);
                                r.mousePress(InputEvent.BUTTON2_MASK);
                            }
                        } else if (id==ID_RIGHT) {
                            if (ival==0) {
                                if (infoFlag)
                                    log("Releasing right button.", MSG.INFO);
                                r.mouseRelease(InputEvent.BUTTON3_MASK);
                            } else {
                                if (infoFlag)
                                    log("Pressing right button.", MSG.INFO);
                                r.mousePress(InputEvent.BUTTON3_MASK);
                            }
                        } else log("Invalid id for action type button: " + actionIdToString(id, null), MSG.WARNING);
                        break;
                    default:
                        log("Invalid registered mouse action type (" + actionTypeToString(type, null) + ")", MSG.WARNING);
                }
            }
        }
    }

    public final static int ACTION_MOVE = 1;
    public final static int ACTION_MOVE_RELATIVE = 2;
    public final static int ACTION_BUTTON = 3;
    public final static int ID_LEFT = 1;
    public final static int ID_RIGHT = 2;
    public final static int ID_MIDDLE = 3;
    public final static int ID_X = 4;
    public final static int ID_Y = 5;
    public final static int ID_WHEEL = 6;

    public static Object parseActionType(String prop, HashMap<String,String> attributes) {
        prop = prop.trim();
        if (prop.equals("move")) return ACTION_MOVE;
        else if (prop.equals("move.rel")) return ACTION_MOVE_RELATIVE;
        else if (prop.equals("button")) return ACTION_BUTTON;
        else throw new IllegalArgumentException("Unknown mouse action type: " + prop);
    }

    public static Object parseActionId(String prop, HashMap<String,String> attributes) {
        prop = prop.trim().toLowerCase();
        if (prop.equals("x")) return ID_X;
        else if (prop.equals("y")) return ID_Y;
        else if (prop.equals("left")) return ID_LEFT;
        else if (prop.equals("right")) return ID_RIGHT;
        else if (prop.equals("middle")) return ID_MIDDLE;
        else if (prop.equals("wheel")) return ID_WHEEL;
        else throw new IllegalArgumentException("Unknown mouse action id: " + prop);
    }

    public static String actionTypeToString(Object prop, HashMap attributes) {
        int type = (Integer)prop;
        switch (type) {
            case ACTION_MOVE:
                return "move";
            case ACTION_MOVE_RELATIVE:
                return "move.rel";
            case ACTION_BUTTON:
                return "button";
            default:
                throw new IllegalArgumentException("Invalid mouse action type code: " + type);
        }
    }

    public static String actionIdToString(Object prop, HashMap attributes) {
        int id = (Integer)prop;
        switch (id) {
            case ID_X: return "x";
            case ID_Y: return "y";
            case ID_LEFT: return "left";
            case ID_MIDDLE: return "middle";
            case ID_WHEEL: return "wheel";
            default: throw new IllegalArgumentException("Unknown mouse action id code: " + prop);
        }
    }

}


